package proxy06;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 利用动态代理实现AOP:
 *   动态:相对于静态代理的静态来说,静态代理在编译时期确定代理类,而动态代理,在程序运行时,由JVM来帮我们动态生成代理类
 * 我们需要借助于java.lang.reflect.Proxy类实现动态代理:
 *   public static Object newProxyInstance(ClassLoader loader,
 *                                           Class<?>[] interfaces,
 *                                           InvocationHandler h)
 *    该方法返回一个实现了指定接口的代理类实例,同时可以将方法的调用指派到相应的调用处理程序
 *    第一个参数:传递一个类加载器,主要作用用来加载我们JVM生成的代理类,我们一般传递和被代理类(老王类)相同的类加载器
 *    第二个参数:其实就是传递的被代理类(老王类)实现的接口(java中一个类可以实现多个接口),目的就是将来
 *             JVM底层生成的代理类也去实现这些接口
 *    第三个参数:传递一个InvocationHandler接口实现类对象,InvocationHanlder负责代理类调用方法处理(InvocationHandler接口接口实现类对象和代理类对象形成一种绑定关系)
 *
 *    返回值: 底层会返回由JVM构造的代理类实例
 *
 * Class类中的方法:
 *   public ClassLoader getClassLoader():获取指定字节码的类加载器
 *   public Class<?>[] getInterfaces() :获取指定类实现的接口
 *
 *  JVM底层生成代理类:
 *    class $Proxy1 implements OneDay{
 *        public void eat(){
 *
 *        }
 *        public void play(){
 *
 *        }
 *        public void sleep(){
 *
 *        }
 *    }
 */
public class Demo {
    @Test
    public void testproxy() {
        //1.构建一个类加载器
        ClassLoader classLoader = LaoWang.class.getClassLoader();

        //2.代理类和被代理类所实现的相同接口
        Class<?>[] interfaces = LaoWang.class.getInterfaces();

        //3.创建InvocationHandler接口的实现类对象
        InvocationHandler ih= new HandlerImpl();

        //4.调用newProxyInstance()方法创建代理类实例
        OneDay proxy = (OneDay) Proxy.newProxyInstance(classLoader, interfaces, ih);//newProxyInstance返回的是代理类对象,而代理类对象实现了和被代理类(老王类)相同的接口
        //因此可以将代理类类型转换成父接口类型,目的是为了调用被代理的方法(eat,play,sleep)
        //多态思想

        //proxy.eat();//通过代理类对象调用的方法最终都会转调到InvocationHandler实现类中重写的invoke方法中
        //proxy.play();
        //proxy.sleep();

        int sum = proxy.getSum(7, 12);
        System.out.println("sum=" + sum);
    }

}
